package com.wave.system.thread;

import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.wave.common.utils.StringUtils;
import com.wave.common.utils.redis.RedisUtils;
import com.wave.common.utils.spring.SpringUtils;
import com.wave.system.domain.SysProduceRecord;
import com.wave.system.domain.SysToolShelfTask;
import com.wave.system.mapper.SysProduceRecordMapper;
import com.wave.system.mapper.SysToolShelfTaskMapper;
import com.wave.system.runner.SystemApplicationRunner;
import com.wave.system.service.ISysProduceArrangeService;
import com.wave.system.service.ISysProductQueryService;
import com.wave.system.util.Modbus4jUtils;
import com.wave.system.util.SnCodeConvertUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

@Component
@Slf4j
public class PlaceMaterialFinishA3ListenerThread implements Runnable {

    private ThreadPoolExecutor threadPoolExecutor = SpringUtils.getBean(ThreadPoolExecutor.class);
    private ISysProduceArrangeService sysProduceArrangeService = SpringUtils.getBean(ISysProduceArrangeService.class);
    private ISysProductQueryService productQueryService = SpringUtils.getBean(ISysProductQueryService.class);
    private SysToolShelfTaskMapper sysToolShelfTaskMapper = SpringUtils.getBean(SysToolShelfTaskMapper.class);
    private SysProduceRecordMapper sysProduceRecordMapper = SpringUtils.getBean(SysProduceRecordMapper.class);


    private static Map<Integer, Integer> map = new HashMap<>();

    static {
        map.put(3, 4122);
        map.put(4, 4123);
    }

    /**
     * A1_SV2~A4_SV2放料完成监听线程
     */
    @Override
    public void run() {
        while (true) {
            try {
                boolean[] booleans = Modbus4jUtils.batchReadCoilStatus(1, 4858, 2);
                int lineNumber;
                for (int i = 0; i < booleans.length; i++) {
                    boolean success = booleans[i];
                    if (success) {
                        lineNumber = i + 3;
                        log.info("PLC上报A{}线放料完成", lineNumber);
                        boolean[] robotStatus = Modbus4jUtils.batchReadCoilStatus(1, 4929, 2);
                        boolean pickUp = robotStatus[0];
                        boolean putDown = robotStatus[1];
                        if (pickUp || putDown) {
                            log.warn("A3机器人取料中或者下料中，不接受错误的放料完成信号");
                            TimeUnit.MILLISECONDS.sleep(100);
                            continue;
                        }
                        // 拼接redisKey，用于获取工装架编号和要处理的物料编码
                        String redisKey = "A" + lineNumber + "_SHELF";
                        String currentSnCodeKey = "A" + lineNumber + "_CURRENT_SN_CODE";
                        // 获取厂线工装架编号
                        String shelfNumber = RedisUtils.getCacheObject(redisKey);
                        String snCode = RedisUtils.getCacheObject(currentSnCodeKey);
                        if (StringUtils.isEmpty(shelfNumber) || StringUtils.isEmpty(snCode)) {
                            log.warn("A3机器人放料完成上位机无法获取{}号线的工装架编号或者获取的物料码为空", lineNumber);
                            TimeUnit.MILLISECONDS.sleep(100);
                            continue;
                        }
                        log.info("A{}线放料完成获取物料编码:{},工装架编号:{}", lineNumber, snCode, shelfNumber);
                        // 获取厂线工装架放置的产品编号，保存生产记录
                        List<String> snCodes = RedisUtils.getCacheObject(shelfNumber);
                        if (CollectionUtils.isEmpty(snCodes)) {
                            snCodes = new ArrayList<>();
                        }
                        //如果工装架物料集合包含当前物料码 则说明当前工装架已放入过该物料码，即当前工装架物料重码了
                        if (snCodes.contains(snCode)) {
                            log.warn("A{}线工装架:{}已放置物料码:{},则说明当前工装架已放入过该物料码，即当前工装架物料重码了", lineNumber, shelfNumber, snCode);
                            /*TimeUnit.MILLISECONDS.sleep(100);
                            continue;*/
                        }
                        SysProduceRecord record = sysProduceRecordMapper.selectOne(Wrappers.lambdaQuery(SysProduceRecord.class).eq(SysProduceRecord::getProductNumber, snCode));
                        if (ObjectUtil.isNotEmpty(record)) {
                            record.setProductNumber(record.getProductNumber() + "@1");
                            sysProduceRecordMapper.updateById(record);
                            log.warn("A{}线物料码:{}已处理,收到重复放料完成信号", lineNumber, snCode);
                            /*TimeUnit.MILLISECONDS.sleep(100);
                            continue;*/
                        }
                        //更新产品查询和工装板任务信息
                        productQueryService.updateTaskQueryInfo(snCode, "抓取完成", shelfNumber, 0);
                        //绑定工装架
                        snCodes.add(snCode);
                        RedisUtils.setCacheObject(shelfNumber, snCodes);
                        //更新工装架任务
                        SysToolShelfTask sysToolShelfTask = sysToolShelfTaskMapper.selectOne(Wrappers.lambdaQuery(SysToolShelfTask.class)
                            .eq(SysToolShelfTask::getShelfNumber, shelfNumber)
                            .ne(SysToolShelfTask::getTaskStatus, "放行完成"));
                        if (ObjectUtil.isNotEmpty(sysToolShelfTask)) {
                            sysToolShelfTask.setTaskStatus("抓取" + snCodes.size() + "个产品");
                            sysToolShelfTask.setProductNumber(SnCodeConvertUtil.getProductCodeBySnCode(snCode));
                            sysToolShelfTaskMapper.updateById(sysToolShelfTask);
                        }
                        //删除芯片版本信息
                        RedisUtils.deleteObject(snCode);

                        TimeUnit.MILLISECONDS.sleep(100);
                        Integer address = map.get(lineNumber);
                        log.info("A{}线物料码:{}上位机放料完成处理完成,通知plc,通讯地址:{}", lineNumber, snCode, address);
                        boolean b = Modbus4jUtils.writeCoil(1, address, true);
                        log.info("A{}线物料码:{},放料完成通知plc结果:{}", lineNumber, snCode, b);
                        //校验是否推送mes&送走工装架
                        sysProduceArrangeService.pushMesCheck(lineNumber, 0);
                        //更新首页机器人wcs任务状态
                        SystemApplicationRunner.armList.get(1).setWcsTaskState("空闲中");
                        //更新首页机械臂的扫码字段
                        SystemApplicationRunner.armList.get(1).setScanSnCode("");
                        log.info("A{}线物料码:{},放料完成删除CCD拍照缓存物料码信息", lineNumber, snCode);
                        RedisUtils.deleteObject(currentSnCodeKey);
                    }
                }
                TimeUnit.MILLISECONDS.sleep(200);
            } catch (Exception e) {
                log.error("A3~A4放料完成监听异常", e);
            }
        }
    }
}
